package com.rtline.business.stream;

/**
 * <p>StreamExamples .
 *
 * <p>change history:
 *
 * <pre>
 * date         defect       person          comments
 * --------------------------------------------------------------------------------
 * 2025/6/7    ********     Tao Ren    create file.
 * </pre>
 *
 * @author Tao Ren
 * @date 2025/6/7 14:01
 */
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamExamples {

    public static void main(String[] args) {
        filterExample();
        mapExample();
        flatMapExample();
        sortedExample();
        distinctExample();
        limitExample();
        skipExample();
        forEachExample();
        reduceExample();
        collectExample();
        matchExample();
        findExample();
        countExample();
        peekExample();
        maxMinExample();
        collectExample2();
        groupingByExample();
        partitioningByExample();
        flatMapToXExample();
        forEachOrderedExample();
        toArrayExample();
        generateExample();
        iterateExample();
        concatExample();
        ofNullableExample();
        parallelExample();
        unorderedExample();
        onCloseExample();
    }

    /**
     * 使用 filter 方法过滤流中的偶数。
     * - 创建一个数字列表。
     * - 使用 filter 方法过滤出偶数。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void filterExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<Integer> evenNumbers = numbers.stream()
                .filter(n -> n % 2 == 0)
                .collect(Collectors.toList());
        System.out.println("Filtered even numbers: " + evenNumbers);
    }

    /**
     * 使用 map 方法将字符串列表中的每个元素转换为大写。
     * - 创建一个字符串列表。
     * - 使用 map 方法将每个字符串转换为大写。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void mapExample() {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        List<String> upperCaseNames = names.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("Mapped upper case names: " + upperCaseNames);
    }

    /**
     * 使用 flatMap 方法将嵌套列表展平。
     * - 创建一个嵌套的整数列表。
     * - 使用 flatMap 方法将每个子列表展平。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void flatMapExample() {
        List<List<Integer>> nestedList = Arrays.asList(
                Arrays.asList(1, 2, 3),
                Arrays.asList(4, 5, 6),
                Arrays.asList(7, 8, 9)
        );
        List<Integer> flatList = nestedList.stream()
                .flatMap(List::stream)
                .collect(Collectors.toList());
        System.out.println("Flattened list: " + flatList);
    }

    /**
     * 使用 sorted 方法对数字列表进行排序。
     * - 创建一个无序的数字列表。
     * - 使用 sorted 方法对数字进行自然排序。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void sortedExample() {
        List<Integer> numbers = Arrays.asList(10, 5, 3, 8, 6, 2, 7, 4, 9, 1);
        List<Integer> sortedNumbers = numbers.stream()
                .sorted()
                .collect(Collectors.toList());
        System.out.println("Sorted numbers: " + sortedNumbers);
    }

    /**
     * 使用 distinct 方法去除数字列表中的重复元素。
     * - 创建一个包含重复数字的列表。
     * - 使用 distinct 方法去除重复元素。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void distinctExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 4, 4, 4);
        List<Integer> distinctNumbers = numbers.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("Distinct numbers: " + distinctNumbers);
    }

    /**
     * 使用 limit 方法限制流中的元素数量。
     * - 创建一个数字列表。
     * - 使用 limit 方法限制流中的元素数量为 5。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void limitExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<Integer> limitedNumbers = numbers.stream()
                .limit(5)
                .collect(Collectors.toList());
        System.out.println("Limited numbers: " + limitedNumbers);
    }

    /**
     * 使用 skip 方法跳过流中的前 n 个元素。
     * - 创建一个数字列表。
     * - 使用 skip 方法跳过前 5 个元素。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void skipExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<Integer> skippedNumbers = numbers.stream()
                .skip(5)
                .collect(Collectors.toList());
        System.out.println("Skipped numbers: " + skippedNumbers);
    }

    /**
     * 使用 forEach 方法对流中的每个元素执行操作。
     * - 创建一个字符串列表。
     * - 使用 forEach 方法对每个字符串执行打印操作。
     */
    public static void forEachExample() {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        names.stream()
                .forEach(name -> System.out.println("Hello, " + name));
    }

    /**
     * 使用 reduce 方法对流中的元素进行归并操作。
     * - 创建一个数字列表。
     * - 使用 reduce 方法计算所有数字的总和。
     */
    public static void reduceExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        int sum = numbers.stream()
                .reduce(0, (a, b) -> a + b);
        System.out.println("Sum of numbers: " + sum);
    }

    /**
     * 使用 collect 方法将流中的元素收集到一个集合中。
     * - 创建一个字符串列表。
     * - 使用 map 方法将每个字符串转换为大写。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void collectExample() {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        List<String> upperCaseNames = names.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("Collected upper case names: " + upperCaseNames);
    }

    /**
     * 使用 allMatch、anyMatch 和 noneMatch 方法检查流中的元素是否满足某些条件。
     * - 创建一个数字列表。
     * - 使用 allMatch 方法检查所有数字是否为偶数。
     * - 使用 anyMatch 方法检查是否有任何数字为偶数。
     * - 使用 noneMatch 方法检查是否没有任何数字为偶数。
     */
    public static void matchExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
        boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
        boolean noneEven = numbers.stream().noneMatch(n -> n % 2 == 0);
        System.out.println("All even: " + allEven);
        System.out.println("Any even: " + anyEven);
        System.out.println("None even: " + noneEven);
    }

    /**
     * 使用 findFirst 和 findAny 方法查找流中的第一个或任意一个元素。
     * - 创建一个数字列表。
     * - 使用 findFirst 方法查找第一个偶数。
     * - 使用 findAny 方法查找任意一个偶数。
     */
    public static void findExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Optional<Integer> firstEven = numbers.stream()
                .filter(n -> n % 2 == 0)
                .findFirst();
        firstEven.ifPresent(System.out::println);

        Optional<Integer> anyEven = numbers.stream()
                .filter(n -> n % 2 == 0)
                .findAny();
        anyEven.ifPresent(System.out::println);
    }

    /**
     * 使用 count 方法统计流中的元素数量。
     * - 创建一个数字列表。
     * - 使用 filter 方法过滤出偶数。
     * - 使用 count 方法统计过滤后的元素数量。
     */
    public static void countExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        long count = numbers.stream()
                .filter(n -> n % 2 == 0)
                .count();
        System.out.println("Count of even numbers: " + count);
    }

    /**
     * 使用 peek 方法在流的中间阶段对每个元素进行调试或日志记录。
     * - 创建一个数字列表。
     * - 使用 peek 方法打印每个处理的数字。
     * - 使用 map 方法对每个数字进行平方操作。
     * - 使用 collect 方法将结果收集到一个新列表中。
     */
    public static void peekExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> squaredNumbers = numbers.stream()
                .peek(n -> System.out.println("Processing: " + n))
                .map(n -> n * n)
                .collect(Collectors.toList());
        System.out.println("Squared numbers: " + squaredNumbers);
    }

    /**
     * 使用 max 和 min 方法找到流中的最大值和最小值。
     * - 创建一个数字列表。
     * - 使用 max 方法找到最大值。
     * - 使用 min 方法找到最小值。
     */
    public static void maxMinExample() {
        List<Integer> numbers = Arrays.asList(10, 5, 3, 8, 6, 2, 7, 4, 9, 1);
        Optional<Integer> max = numbers.stream().max(Integer::compare);
        Optional<Integer> min = numbers.stream().min(Integer::compare);
        System.out.println("Max number: " + max.orElse(null));
        System.out.println("Min number: " + min.orElse(null));
    }

    /**
     * 使用 collect 方法的其他收集器将流中的元素收集到不同的数据结构中。
     * - 创建一个字符串列表。
     * - 使用 joining 收集器将字符串连接成一个字符串。
     * - 使用 toMap 收集器将字符串按长度分组。
     */
    public static void collectExample2() {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
        String concatenatedNames = names.stream()
                .collect(Collectors.joining(", "));
        System.out.println("Concatenated names: " + concatenatedNames);

        Map<Integer, String> nameMap = names.stream()
                .collect(Collectors.toMap(s -> s.length(), s -> s,(a,b)->a));
        System.out.println("Name map: " + nameMap);
    }

    /**
     * 使用 groupingBy 方法对流中的元素进行分组。
     * - 创建一个字符串列表。
     * - 使用 groupingBy 方法按字符串长度分组。
     */
    public static void groupingByExample() {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
        Map<Integer, List<String>> namesByLength = names.stream()
                .collect(Collectors.groupingBy(String::length));
        System.out.println("Names grouped by length: " + namesByLength);
    }

    /**
     * 使用 partitioningBy 方法将流中的元素分为两部分。
     * - 创建一个数字列表。
     * - 使用 partitioningBy 方法将数字分为偶数和奇数两部分。
     */
    public static void partitioningByExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Map<Boolean, List<Integer>> partitionedNumbers = numbers.stream()
                .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println("Partitioned numbers: " + partitionedNumbers);
    }

    /**
     * 使用 flatMapToInt、flatMapToDouble 和 flatMapToLong 方法将流中的元素映射为原始类型的流。
     * - 创建一个字符串列表，每个字符串包含逗号分隔的数字。
     * - 使用 flatMapToInt 方法将字符串映射为整数流。
     * - 计算所有数字的总和。
     */
    public static void flatMapToXExample() {
        List<String> numbers = Arrays.asList("1,2", "3,4", "5,6");
        int sum = numbers.stream()
                .flatMapToInt(s -> Arrays.stream(s.split(",")).mapToInt(Integer::parseInt))
                .sum();
        System.out.println("Sum of numbers: " + sum);
    }

    /**
     * 使用 forEachOrdered 方法保证元素的处理顺序与流中的顺序一致。
     * - 创建一个字符串列表。
     * - 使用 forEachOrdered 方法按顺序打印每个字符串。
     */
    public static void forEachOrderedExample() {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        names.stream()
                .forEachOrdered(name -> System.out.println("Hello, " + name));
    }

    /**
     * 使用 toArray 方法将流中的元素收集到一个数组中。
     * - 创建一个数字列表。
     * - 使用 toArray 方法将流中的元素收集到一个数组中。
     */
    public static void toArrayExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        Object[] numberArray = numbers.stream().toArray();
        System.out.println("Number array: " + Arrays.toString(numberArray));
    }

    /**
     * 使用 generate 方法生成一个无限流。
     * - 使用 generate 方法生成一个包含随机数的无限流。
     * - 使用 limit 方法限制流的大小为 5。
     */
    public static void generateExample() {
        Stream<Double> randomNumbers = Stream.generate(Math::random).limit(5);
        randomNumbers.forEach(System.out::println);
    }

    /**
     * 使用 iterate 方法生成一个无限流。
     * - 使用 iterate 方法生成一个从 0 开始的偶数无限流。
     * - 使用 limit 方法限制流的大小为 5。
     */
    public static void iterateExample() {
        Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2).limit(5);
        evenNumbers.forEach(System.out::println);
    }

    /**
     * 使用 concat 方法将两个流合并为一个流。
     * - 创建两个数字流。
     * - 使用 concat 方法将两个流合并。
     */
    public static void concatExample() {
        Stream<Integer> stream1 = Stream.of(1, 2, 3);
        Stream<Integer> stream2 = Stream.of(4, 5, 6);
        Stream<Integer> combinedStream = Stream.concat(stream1, stream2);
        combinedStream.forEach(System.out::println);
    }

    /**
     * 使用 ofNullable 方法创建一个可能包含单个元素的流。
     * - 使用 ofNullable 方法创建一个包含字符串的流。
     * - 如果元素为 null，则创建一个空流。
     */
    public static void ofNullableExample() {
        Stream<String> stream1 = Stream.ofNullable("Hello");
        Stream<String> stream2 = Stream.ofNullable(null);
        stream1.forEach(System.out::println);
        stream2.forEach(System.out::println);
    }

    /**
     * 使用 isParallel 和 sequential 方法检查流是否为并行流，并将并行流转换为顺序流。
     * - 创建一个数字流并将其转换为并行流。
     * - 检查流是否为并行流。
     * - 将并行流转换为顺序流。
     */
    public static void parallelExample() {
        Stream<Integer> parallelStream = Stream.of(1, 2, 3, 4, 5).parallel();
        System.out.println("Is parallel: " + parallelStream.isParallel());
        Stream<Integer> sequentialStream = parallelStream.sequential();
        System.out.println("Is sequential: " + !sequentialStream.isParallel());
    }

    /**
     * 使用 unordered 方法将流标记为无序。
     * - 创建一个数字流并将其标记为无序。
     */
    public static void unorderedExample() {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5).unordered();
        stream.forEach(System.out::println);
    }

    /**
     * 使用 onClose 方法在流关闭时执行指定的操作。
     * - 创建一个数字流并在流关闭时打印一条消息。
     */
    public static void onCloseExample() {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5).onClose(() -> System.out.println("Stream is closed"));
        stream.forEach(System.out::println);
    }
}
